package com.superhelper.processor.order.consumer;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.aliyun.openservices.ons.api.Consumer;
import com.superhelper.common.Consts;
import com.superhelper.common.domain.AuserDeliver;
import com.superhelper.common.domain.AuserShop;
import com.superhelper.common.domain.DeliverRecord;
import com.superhelper.common.domain.DeliverRecordStatus;
import com.superhelper.common.domain.ExtMsg;
import com.superhelper.common.domain.LoginLog;
import com.superhelper.common.domain.OrderCategory;
import com.superhelper.common.domain.POIStatus;
import com.superhelper.common.domain.POIStatusOperator;
import com.superhelper.common.domain.PushMsgType;
import com.superhelper.common.domain.TakeOutOrder;
import com.superhelper.common.domain.TakeOutOrderProcess;
import com.superhelper.common.domain.TakeOutOrderStatus;
import com.superhelper.common.domain.TakeOutOrderType;
import com.superhelper.common.domain.Task;
import com.superhelper.common.domain.User;
import com.superhelper.common.exception.ServiceException;
import com.superhelper.common.mapper.DeliverMapper;
import com.superhelper.common.mapper.DeliverRecordMapper;
import com.superhelper.common.mapper.TakeOutOrderMapper;
import com.superhelper.common.mapper.TaskMapper;
import com.superhelper.common.mapper.UserMapper;
import com.superhelper.common.service.PushService;
import com.superhelper.common.service.RedisService;
import com.superhelper.common.utils.DateTimeUtil;
import com.superhelper.common.utils.JsonHelper;

public abstract class AbstractOrderConsumer {

    protected final Logger log = LoggerFactory.getLogger(getClass());

    protected Consumer consumer;
    @Autowired
    protected TakeOutOrderMapper orderMapper;
    @Autowired
    protected UserMapper userMapper;

    @Autowired
    protected DeliverMapper deliverMapper;
    @Autowired
    protected DeliverRecordMapper deliverRecordMapper;
    @Autowired
    protected TaskMapper taskMapper;
    @Autowired
    protected RedisService redis;
    @Autowired
    protected PushService pushService;

    public void dealOrder(String status, String msg, PushMsgType msgType, String orderType) {
        @SuppressWarnings({ "unchecked" })
        Map<String, Object> msgObj = JsonHelper.fromJson(msg, Map.class);
        String plfOrderId = msgObj.get("orderId") + "";
        TakeOutOrder order = orderMapper.getByPlfOrderIdAndType(plfOrderId, orderType);
        if (order == null) {
            throw new ServiceException();
        }
        if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.VALID.getValue())) {
            orderMapper.updateAccepted(plfOrderId, orderType);
            order.setValidAt(new Date());
            try {
                addProcessInfo(order);
                addDeliverInfo(order);
            } catch (Throwable e) {
                log.error("error ", e);
            }
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.SETTLED.getValue())) {
            orderMapper.updateSettled(plfOrderId, orderType);
            this.updateUser(plfOrderId, orderType);
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.INVALID.getValue())) {
            String reason = (String) msgObj.get("reason");
            String reasonCode = msgObj.get("reasonCode") + "";
            orderMapper.updateInvalid(plfOrderId, orderType, StringUtils.defaultString(reason, "已取消"));
            if (orderType.equals(TakeOutOrderType.MeiTuan.getValue())) {// 取消单打印
                long time = System.currentTimeMillis() / 1000;
                long ctime = order.getCreateAt().getTime() / 1000;
                if (time - ctime < 120) {
                    order.setStatus(TakeOutOrderStatus.INVALID.getValue());// 变为取消
                    this.addProcessInfo(order);
                }
            }
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.REFUNDING.getValue())) {
            String notifyType = (String) msgObj.get("notifyType");

            String reason = (String) msgObj.get("reason");
            if (StringUtils.endsWithIgnoreCase("reject", notifyType)
                    || StringUtils.endsWithIgnoreCase("cancelRefund", notifyType)
                    || StringUtils.endsWithIgnoreCase("cancelRefundComplaint", notifyType)) {
                orderMapper.updateCallBack(plfOrderId, orderType, StringUtils.defaultString(reason, "退款已取消"));
            } else if (StringUtils.endsWithIgnoreCase("agree", notifyType)) {
                orderMapper.updateInvalid(plfOrderId, orderType, StringUtils.defaultString(reason, "已确认退款"));
            } else {
                orderMapper.updateRefunding(plfOrderId, orderType, StringUtils.defaultString(reason, "申请退款中"));
            }
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.APPLY_CANCEL.getValue())) {
            String reason = (String) msgObj.get("reason");
            orderMapper.updateApplyCancel(plfOrderId, orderType, StringUtils.defaultString(reason, "申请取消"));
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.REJECT_CANCEL.getValue())) {
            String reason = (String) msgObj.get("reason");
            // 查看快递单状态
            DeliverRecord dr = deliverRecordMapper.getLastlyByOrderId(order.getId());
            // 非配送或者完成状态，则都指定外卖单为有效状态
            if (dr == null || dr.getStatus() <= DeliverRecordStatus.picking.getVal()
                    || dr.getStatus() > DeliverRecordStatus.completed.getVal()) {
                orderMapper.updateValid(plfOrderId, orderType, StringUtils.defaultString(reason, "拒绝取消"));
            } else if (dr.getStatus() == DeliverRecordStatus.delivering.getVal()) {
                orderMapper.updateDeliveringById(order.getId());
            } else if (dr.getStatus() == DeliverRecordStatus.completed.getVal()) {
                orderMapper.updateSettledById(order.getId());
            }
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.DELIVERING.getValue())) {
            orderMapper.updateDeliveringById(order.getId());
        } else if (StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.REVOKE_REFUND.getValue())) {
            orderMapper.updateCallBack(plfOrderId, orderType, "退款已取消");
        }

        if (!StringUtils.equalsIgnoreCase(status, TakeOutOrderStatus.INVALID.getValue())) {
            publish(order, msgType, false);
        }
    }

    protected void publish(TakeOutOrder order, PushMsgType msgType, boolean retry) {

        if (PushMsgType.ORDER_APPLY_CANCEL.getValue().equals(msgType.getValue())) {
            msgType = PushMsgType.ORDER_CANCELED;
        }
        Map<String, Object> msgMap = new HashMap<>();
        msgMap.put("orderId", order.getId());
        msgMap.put("type", msgType.getValue());
        msgMap.put("shop_type", order.getType());
        msgMap.put("book", order.getBook());
        msgMap.put("retry", retry);

        AuserShop shop = orderMapper.getShop(order.getShopId(), order.getType());
        if (shop.getOrderAuto() == 3
                && (msgType.equals(PushMsgType.ORDER_CREATED) || msgType.equals(PushMsgType.ORDER_ACCEPTED))) { // wifi打印，后台自动接单。
            String key = Consts.Redis.WIFI_ORDER;
            String msg = JsonHelper.toJson(msgMap);
            log.info("{},msg:{}", key, msg);
            redis.listPushTail(key, msg);
        } else {
            // pc端是否在线
            String online_key = String.format(Consts.Redis.USER_ONLINE, shop.getAuserId());
            @SuppressWarnings("rawtypes")
            Map user = redis.get(online_key, Map.class);
            log.info("onlineKey,value:{}", user);
            if (user != null) {// pc
                String key = String.format(Consts.Redis.SUB_ORDER, order.getType(), order.getShopId());
                String msg = JsonHelper.toJson(msgMap);
                redis.listPushTail(key, msg);
                log.info("publish key:{},value:{}", key, msg);
            }

            // app推送
            String title = "您有新消息";
            ExtMsg extras = new ExtMsg("order", msgMap);
            // 最后登录的信息
            String logKey = Consts.Redis.USER_LOGIN_PREFIX + shop.getAuserId();
            LoginLog userLog = redis.get(logKey, LoginLog.class);
            if (userLog != null) {
                pushService.push(title, title, title, userLog.getImid(), userLog.getDevice(), extras);
                log.info("publish imid:{},value:{}", userLog.getImid(), msgMap);
            }
        }
    }

    public int updateUser(String plfOrderId, String type) {
        TakeOutOrder order = orderMapper.getByPlfOrderIdAndType(plfOrderId, type);
        AuserShop shop = orderMapper.getShop(order.getShopId(), order.getType());
        User user = userMapper.getUser(order.getPhone(), shop.getAuserId());
        if (user != null) {
            user.setPhone(order.getPhone());
            user.setAuserId(shop.getAuserId());
            if (type.equals(TakeOutOrderType.EleMe.getValue())) {
                user.setEle_money(BigDecimal.valueOf(order.getTotalPrice()).add(user.getEle_money()));
            } else {
                user.setMt_money(BigDecimal.valueOf(order.getTotalPrice()).add(user.getMt_money()));
            }
            user.setIntegral(BigDecimal.valueOf(order.getTotalPrice()).intValue() + user.getIntegral());
            return userMapper.updateUser(user);
        }
        return 0;
    }

    /**
     * 增加一条记录，用于控制是否发单，是否打印，避免重复
     */
    protected void addProcessInfo(TakeOutOrder order) {
        TakeOutOrderProcess toop = new TakeOutOrderProcess();
        toop.setOrderId(order.getId());
        toop.setDeliver_state(0);
        toop.setPrint_state(0);
        toop.setShopId(order.getShopId());
        if (order.getStatus().equals(TakeOutOrderStatus.INVALID.getValue())) {
            toop.setType(1);
        }
        TakeOutOrderProcess processor = orderMapper.getProcessInfo(toop.getOrderId(), toop.getType());
        if (processor != null) {
            return;
        }
        AuserShop aShop = orderMapper.getShop(order.getShopId(), order.getType());
        if (aShop != null && aShop.getOrderAuto() != 0) { // 关闭自动接单
            log.info("orderId:{} not need addProcessInfo", order.getId());
            orderMapper.addProcessInfo(toop);
        }
    }

    public void addDeliverInfo(TakeOutOrder order) {
        AuserShop shop = orderMapper.getShop(order.getShopId(), order.getType());
        if (shop.getDeliverType() == null || shop.getDeliverType() != 1) { // 1：达达自动发单
            log.info("orderId:{} not need deliver,getDeliverType != 1 or is null", order.getId());
            // 非平台配送
            return;
        }
        // if (shop.getDeliverAuto() == null || shop.getDeliverAuto() != 1) {
        // log.info("orderId:{} not need deliver, getDeliverAuto != 0 or is
        // null",
        // order.getId());
        // // 不需要自动配送
        // return;
        // }
        AuserDeliver deliver = deliverMapper.getAuserDeliverByShopIdAndShopType(order.getShopId(), order.getType());
        // 关闭自动发单，则是手动发单
        // if (deliver == null || deliver.getState() == 0) {
        // return;
        // }
        int orderCategory = OrderCategory.normal.getVal();
        if (order.getDeliverTime() != null) {
            orderCategory = OrderCategory.book.getVal();
        } else if (order.getTotalPrice() > deliver.getGt_money().doubleValue()) {
            orderCategory = OrderCategory.big.getVal();
        }
        DeliverRecord dr = new DeliverRecord();
        dr.setOrderCategory(orderCategory);
        dr.setStatus(DeliverRecordStatus.unsend.getVal());
        dr.setDeliverFee(0d);
        dr.setDeliverNo(null);
        dr.setCreateAt(new Date());
        dr.setCurrentTip(0d);
        dr.setPerTip(deliver.getPart_money().doubleValue());
        dr.setMaxTip(deliver.getMax_money().doubleValue());
        dr.setDeliverAt(new Date());
        dr.setOrderId(order.getId());
        dr.setExtId(0);
        dr.setAuserShopId(shop.getId());
        Date deliverAt = addDeliverRecord(order, deliver, dr);
        Task task = new Task();
        task.setFlag(0);
        task.setRetryTimes(0);
        task.setType(Consts.Task.deliver_record);
        task.setNextTime(deliverAt);
        task.setObjId(dr.getId() + "");
        if (taskMapper.hasTask(task.getType(), task.getObjId()) > 0) {
            log.info("Has Task:{}", task);
            return;
        }
        taskMapper.addTask(task);
    }

    private Date addDeliverRecord(TakeOutOrder order, AuserDeliver deliverConf, DeliverRecord dr) {

        // 如果是非预定订单，而且不是大金额订单，则比较复杂，乐观锁去重复更新
        if (dr.getOrderCategory() == OrderCategory.normal.getVal()) {

            while (!addNormal(dr, deliverConf, order))
                ;
            return dr.getDeliverAt();
        } else {
            Date nextTime = null;
            if (dr.getOrderCategory() == OrderCategory.big.getVal()) {
                nextTime = DateTimeUtil.addNSeconds(order.getValidAt(), deliverConf.getDelay_sec());
            } else {
                // 否则就是预订单
                nextTime = order.getDeliverTime();
                // 如果没有配置，默认是10分钟前发送订单
                int addMinute = 10;
                if (order.getDist() < 1) {
                    addMinute = deliverConf.getOne_km_minute();
                } else if (order.getDist() < 2) {
                    addMinute = deliverConf.getTwo_km_minute();
                } else if (order.getDist() < 3) {
                    addMinute = deliverConf.getThird_km_minute();
                } else {
                    addMinute = deliverConf.getOther_km_minute();
                }
                nextTime = DateTimeUtil.addNMinutes(nextTime, -addMinute);
            }
            dr.setDeliverAt(nextTime);

            deliverRecordMapper.addDeliverRecord(dr);
            return nextTime;
        }
    }

    private boolean addNormal(DeliverRecord dr, AuserDeliver deliverConf, TakeOutOrder order) {
        /**
         * 默认查60分钟内的数据，60分钟后才有一单，其实不用考虑间隔问题
         */
        DeliverRecord lastlyRecord = null;
        lastlyRecord = deliverRecordMapper.getLastlyDeliverRecord(dr.getAuserShopId(), dr.getOrderCategory(),
                DateTimeUtil.addNMinutes(new Date(), -60));
        Date deliverAt = null;
        Date time1 = DateTimeUtil.addNSeconds(order.getValidAt(), deliverConf.getNormal_sec());
        if (lastlyRecord == null) {
            deliverAt = time1;
        } else {
            Date time2 = DateTimeUtil.addNSeconds(lastlyRecord.getDeliverAt(), deliverConf.getInterval_sec());
            // 如果订单的创建时间是在上一单的快递时间加上间隔时间之后，那么直接就加上接单后延时发的秒数就好
            if (order.getValidAt().after(time2)) {
                deliverAt = time1;
            } else {
                if (time1.before(time2)) {
                    deliverAt = time2;
                } else {
                    deliverAt = time1;
                }
            }
        }

        Integer version = orderMapper.getVersionById(dr.getAuserShopId());

        if (orderMapper.updateVersionById(dr.getAuserShopId(), version) > 0) {
            dr.setDeliverAt(deliverAt);
            try {
                deliverRecordMapper.addDeliverRecord(dr);
                return true;
            } catch (Exception e) {
                // don't care
                if (deliverRecordMapper.hasOrderId(dr.getOrderId(), 0) > 0) {
                    // 已经插入过了，就默认为true
                    return true;
                }
                // 更新错误，就重复更新一次
            }
        }
        return false;
    }

    protected void publishShopStatus(String shopId, TakeOutOrderType orderType, POIStatus poiStatus,
            POIStatusOperator poiStatusOperator, String reason) {
        // TODO 发送店铺消息
        Map<String, Object> msgMap = new HashMap<>();
        msgMap.put("shopId", shopId);
        msgMap.put("type", PushMsgType.POI_STATUS.getValue());
        msgMap.put("shop_type", orderType.getValue());
        AuserShop shop = orderMapper.getShop(shopId, orderType.getValue());
        // app推送
        String title = "您有新消息";
        ExtMsg extras = new ExtMsg("shop", msgMap);
        // 最后登录的信息
        String logKey = Consts.Redis.USER_LOGIN_PREFIX + shop.getAuserId();
        LoginLog userLog = redis.get(logKey, LoginLog.class);
        if (userLog != null) {
            pushService.push(title, title, title, userLog.getImid(), userLog.getDevice(), extras);
            log.info("publishShopStatus imid:{},value:{}", userLog.getImid(), msgMap);
            String key = Consts.Redis.SUPER_SHOP + orderType.getValue() + shopId;
            redis.delKey(key);
        }
    }

    public static void main(String[] args) {
        DeliverRecord lastlyRecord = null;
        Date validAt = DateTimeUtil.parseDatetime("2017-05-24 12:00:00");
        test(lastlyRecord, validAt);

        validAt = DateTimeUtil.parseDatetime("2017-05-24 12:00:05");
        lastlyRecord = new DeliverRecord();
        lastlyRecord.setDeliverAt(DateTimeUtil.parseDatetime("2017-05-24 12:10:00"));
        test(lastlyRecord, validAt);

        validAt = DateTimeUtil.parseDatetime("2017-05-24 12:00:05");
        lastlyRecord = new DeliverRecord();
        lastlyRecord.setDeliverAt(DateTimeUtil.parseDatetime("2017-05-24 12:01:00"));
        test(lastlyRecord, validAt);

        validAt = DateTimeUtil.parseDatetime("2017-05-24 12:01:00");
        lastlyRecord = new DeliverRecord();
        lastlyRecord.setDeliverAt(DateTimeUtil.parseDatetime("2017-05-24 12:01:00"));
        test(lastlyRecord, validAt);

        validAt = DateTimeUtil.parseDatetime("2017-05-24 12:02:00");
        lastlyRecord = new DeliverRecord();
        lastlyRecord.setDeliverAt(DateTimeUtil.parseDatetime("2017-05-24 12:01:00"));
        test(lastlyRecord, validAt);
    }

    public static void test(DeliverRecord lastlyRecord, Date validAt) {
        Date deliverAt = null;

        Date time1 = DateTimeUtil.addNSeconds(validAt, 60);
        if (lastlyRecord == null) {
            deliverAt = time1;
            System.out.println(1111111);
        } else {
            Date time2 = DateTimeUtil.addNSeconds(lastlyRecord.getDeliverAt(), 30);
            // 如果订单的创建时间是在上一单的快递时间加上间隔时间之后，那么直接就加上接单后延时发的秒数就好
            if (validAt.after(time2)) {
                deliverAt = time1;
                System.out.println(2222222);
            } else {
                if (time1.before(time2)) {
                    deliverAt = time2;
                    System.out.println(3333333);
                } else {
                    deliverAt = time1;
                    System.out.println(4444444);
                }
            }
        }
        System.out.println(" 上一个订单的发送时间"
                + (lastlyRecord == null ? " 【无】" : DateTimeUtil.formatDatetime(lastlyRecord.getDeliverAt())) + "  下单时间："
                + DateTimeUtil.formatDatetime(validAt) + "  发送时间：" + DateTimeUtil.formatDatetime(deliverAt));
    }

}
